import { EnvironmentProviders, Injectable, Provider, inject, provideAppInitializer } from '@angular/core';
import { Router } from '@angular/router';
import { ACLService } from '@delon/acl';
import { DA_SERVICE_TOKEN, JWTTokenModel } from '@delon/auth';
import { ALAIN_I18N_TOKEN, MenuIcon, MenuService, SettingsService, TitleService, _HttpClient } from '@delon/theme';
import type { NzSafeAny } from 'ng-zorro-antd/core/types';
import { Observable, catchError, map, zip } from 'rxjs';
import { ResponseCode } from 'src/app/shared/response.code';

import { I18NService } from '../i18n/i18n.service';

/**
 * 首页菜单
 */
const dashbordMenu = [
  {
    text: '主导航',
    i18n: 'menu.main',
    group: true,
    hideInBreadcrumb: true,
    children: [
      {
        text: '仪表盘',
        i18n: 'menu.dashboard',
        icon: 'anticon-dashboard',
        children: [
          {
            text: '工作台',
            link: '/dashboard/workplace',
            i18n: 'menu.dashboard.workplace'
          }
        ]
      }
    ]
  }
];

/**
 * Used for application startup
 * Generally used to get the basic data of the application, like: Menu Data, User Data, etc.
 */
export function provideStartup(): Array<Provider | EnvironmentProviders> {
  return [
    StartupService,
    provideAppInitializer(() => {
      const initializerFn = (
        (startupService: StartupService) => () =>
          startupService.load()
      )(inject(StartupService));
      return initializerFn();
    })
  ];
}

@Injectable()
export class StartupService {
  private tokenService = inject(DA_SERVICE_TOKEN);

  private menuService = inject(MenuService);
  private settingService = inject(SettingsService);
  private aclService = inject(ACLService);
  private titleService = inject(TitleService);
  private httpClient = inject(_HttpClient);
  private router = inject(Router);
  private i18n = inject<I18NService>(ALAIN_I18N_TOKEN);

  private viaI18n(): Observable<void> {
    const defaultLang = this.i18n.defaultLang;
    return this.i18n.loadLangData(defaultLang).pipe(
      map((langData: NzSafeAny) => {
        this.i18n.use(defaultLang, langData);
      })
    );
  }

  private reload(): Observable<void> {
    const defaultLang = this.i18n.defaultLang;
    return zip(this.i18n.loadLangData(defaultLang), this.httpClient.get('api/portal/index/current')).pipe(
      // 接收其他拦截器后产生的异常消息
      catchError(res => {
        console.warn(`StartupService.load: Network request failed`, res);
        this.viaI18n().subscribe(() => {
          if (res.status == 401) {
            this.tokenService.clear();
            this.router.navigateByUrl(this.tokenService.login_url!);
            localStorage.clear();
          } else {
            this.router.navigateByUrl(`/exception/500`);
          }
        });
        // setTimeout(() => this.router.navigateByUrl(`/exception/500`));
        return [];
      }),
      map(([langData, res]: [Record<string, string>, NzSafeAny]) => {
        // setting language data
        this.i18n.use(defaultLang, langData);
        if (res && res.code == ResponseCode.SUCCESS) {
          const appData = res.data;
          // Application data
          // Application information: including site name, description, year
          this.settingService.setApp(appData.app);
          // User information: including name, avatar, email address
          this.settingService.setUser(appData.user);
          // ACL: Set the permissions to full, https://ng-alain.com/acl/getting-started
          this.aclService.setFull(true);
          // Menu data, https://ng-alain.com/theme/menu
          if (!appData.menu) {
            appData.menu = [];
          }
          this.recursiveMenu(appData.menu);
          appData.menu = dashbordMenu.concat(appData.menu);
          this.menuService.add(appData.menu);
          // Can be set page suffix title, https://ng-alain.com/theme/title
          this.titleService.suffix = appData.app.name;
        }
      })
    );
  }

  recursiveMenu(menus: NzSafeAny[]) {
    menus.forEach((element: NzSafeAny) => {
      if (element.icon) {
        const icon: MenuIcon = { type: 'icon', value: element.icon };
        // TODO 颜色填充
        // if (element.fill) {
        //   icon.theme = 'twotone';
        //   icon.twoToneColor = element.fill;
        // }
        element.icon = icon;
      }
      if (element.children) {
        this.recursiveMenu(element.children);
      }
    });
  }

  refreshCurrent() {
    return this.httpClient.get('api/portal/index/current').subscribe((res: NzSafeAny) => {
      if (res && res.code == ResponseCode.SUCCESS) {
        const appData = res.data;
        // Application data
        // Application information: including site name, description, year
        this.settingService.setApp(appData.app);
        // User information: including name, avatar, email address
        this.settingService.setUser(appData.user);
        // ACL: Set the permissions to full, https://ng-alain.com/acl/getting-started
        this.aclService.setFull(true);
        // Menu data, https://ng-alain.com/theme/menu
        if (!appData.menu) {
          appData.menu = [];
        }
        appData.menu = dashbordMenu.concat(appData.menu);
        this.recursiveMenu(appData.menu);
        this.menuService.add(appData.menu);
        // Can be set page suffix title, https://ng-alain.com/theme/title
        this.titleService.suffix = appData.app.name;
      }
    });
  }

  load(): Observable<void> {
    let jwtTkoen = this.tokenService.get(JWTTokenModel);
    if (jwtTkoen?.token) {
      let now = new Date();
      if (jwtTkoen['exp'] < now.getTime()) {
        this.tokenService.clear();
      }
      return this.reload();
    }
    return this.viaI18n();
  }
}
